"""
热量消耗记录 DAO 层
负责数据库交互，仅处理数据操作，不包含业务逻辑
"""
from datetime import date
from typing import Optional

from app.db import db
from app.Models.HealthModels.KcalRecordModel import KcalRecord


class KcalRecordDAO:
    @staticmethod
    def add(record: KcalRecord) -> bool:
        """
        新增热量记录
        :param record: KcalRecord 实例
        :return: True-新增成功，False-新增失败
        """
        try:
            db.session.add(record)
            db.session.commit()
            return True
        except Exception:
            db.session.rollback()
            return False

    @staticmethod
    def delete(record_id: int) -> bool:
        """
        根据记录ID删除热量记录
        :param record_id: 记录主键ID
        :return: True-删除成功（含记录不存在），False-删除失败
        """
        try:
            record = KcalRecord.query.get(record_id)
            if record:
                db.session.delete(record)
                db.session.commit()
            return True  # 记录不存在视为删除成功（幂等性）
        except Exception:
            db.session.rollback()
            return False

    @staticmethod
    def update(record: KcalRecord) -> bool:
        """
        更新热量记录（需传入完整的实例，含主键ID）
        :param record: 已存在的 KcalRecord 实例（必须包含 id）
        :return: True-更新成功，False-更新失败（含记录不存在）
        """
        try:
            # 先验证记录是否存在
            exist_record = KcalRecord.query.get(record.id)
            if not exist_record:
                return False

            # 批量更新字段（排除主键）
            for col in KcalRecord.__table__.columns:
                if col.name != 'id':  # 主键不允许修改
                    setattr(exist_record, col.name, getattr(record, col.name, None))

            db.session.commit()
            return True
        except Exception:
            db.session.rollback()
            return False

    @staticmethod
    def get_by_id(record_id: int) -> Optional[KcalRecord]:
        """
        根据ID查询单条记录
        :param record_id: 记录主键ID
        :return: 存在返回 KcalRecord 实例，不存在返回 None
        """
        try:
            return KcalRecord.query.get(record_id)
        except Exception:
            return None

    @staticmethod
    def get_by_user_date(user_id: int, kcal_date: date) -> Optional[KcalRecord]:
        """
        根据用户ID和记录日期查询单条记录（用户+日期唯一）
        :param user_id: 用户ID
        :param kcal_date: 记录日期
        :return: 存在返回 KcalRecord 实例，不存在返回 None
        """
        try:
            return KcalRecord.query.filter(
                KcalRecord.user_id == user_id,
                KcalRecord.kcal_date == kcal_date
            ).first()
        except Exception:
            return None

    @staticmethod
    def get_by_user(user_id: int, page: int = 1, per_page: int = 30) -> list[KcalRecord]:
        """
        根据用户ID分页查询记录（按日期倒序）
        :param user_id: 用户ID
        :param page: 页码（默认第1页）
        :param per_page: 每页条数（默认30条）
        :return: 记录列表（空列表表示无数据或查询失败）
        """
        try:
            pagination = KcalRecord.query.filter(
                KcalRecord.user_id == user_id
            ).order_by(KcalRecord.kcal_date.desc()).paginate(
                page=page, per_page=per_page, error_out=False
            )
            return pagination.items
        except Exception:
            return []

    @staticmethod
    def get_by_date_range(user_id: int, start_date: date, end_date: date) -> list[KcalRecord]:
        """
        根据用户ID和日期范围查询记录（按日期正序）
        :param user_id: 用户ID
        :param start_date: 开始日期
        :param end_date: 结束日期
        :return: 记录列表（空列表表示无数据或查询失败）
        """
        try:
            return KcalRecord.query.filter(
                KcalRecord.user_id == user_id,
                KcalRecord.kcal_date >= start_date,
                KcalRecord.kcal_date <= end_date
            ).order_by(KcalRecord.kcal_date.asc()).all()
        except Exception:
            return []

    @staticmethod
    def batch_add(records: list[KcalRecord]) -> bool:
        """
        批量新增热量记录
        :param records: KcalRecord 实例列表
        :return: True-全部成功，False-批量失败（会回滚所有操作）
        """
        if not records:
            return True  # 空列表视为成功（幂等性）

        try:
            db.session.add_all(records)
            db.session.commit()
            return True
        except Exception:
            db.session.rollback()
            return False

    @staticmethod
    def batch_delete(record_ids: list[int]) -> bool:
        """
        批量删除热量记录
        :param record_ids: 记录ID列表
        :return: True-全部成功，False-批量失败（会回滚所有操作）
        """
        if not record_ids:
            return True  # 空列表视为成功（幂等性）

        try:
            KcalRecord.query.filter(KcalRecord.id.in_(record_ids)).delete(synchronize_session=False)
            db.session.commit()
            return True
        except Exception:
            db.session.rollback()
            return False
